package com.fortify.awb.bugtracker;

import java.util.LinkedList;
import java.util.List;

/**
 * This class represents a specific field that will be submitted to the repository during bug submission.
 * Instances of this class are typically contained in a {@link BugtrackerFields} collection.
 */
public class BugtrackerField  {

	/**
	 * The name of the field that will be displayed to the user in the "File Bug" dialog.
	 */
	private String displayName;

	/**
	 * The internal name of the field in the bug repository
	 */
	private String targetName;

	/**
	 * The default value of the field, if one exists
	 */
	private String defaultValue;

	/**
	 * The possible values of the field.  If the possible values are specified, then you cannot assign
	 * the value of this field to something other than a possible value
	 */
	private List<String> possibleValues;

	/**
	 * The value of this field.  If the possible values are specified, then this must be
	 * equal to a possible value
	 */
	private String value;

	/**
	 * The listeners for this field.  The listeners will be notified when {@link #setValue(String)} is invoked.
	 */
	private List<BugtrackerFieldListener> fieldListeners = new LinkedList<BugtrackerFieldListener>();

	/**
	 * Create a field with the specified display name, target name, and default value
	 */
	public BugtrackerField(String displayName, String targetName, String defaultValue) {
		super();
		setDisplayName(displayName);
		setTargetName(targetName);
		setDefaultValue(defaultValue);
	}

	/**
	 * Create a field with the specified display name, target name, and default value, and possible values
	 */
	public BugtrackerField(String displayName, String targetName, String defaultValue, List<String> possibleValues) {
		super();
		setDisplayName(displayName);
		setTargetName(targetName);
		setDefaultValue(defaultValue);
		setPossibleValues(possibleValues);
	}

	/**
	 * Create a field
	 */
	public BugtrackerField() {
	}

	/**
	 * Returns the name of the field that will be displayed to the user in the "File Bug" dialog.
	 *
	 * @return the name of the field that will be displayed to the user in the "File Bug" dialog.
	 */
	public String getDisplayName() {
		return this.displayName;
	}

	/**
	 * Returns the name of the field that will be displayed to the user in the "File Bug" dialog.
	 *
	 * @param name the name of the field that will be displayed to the user in the "File Bug" dialog.
	 */
	public void setDisplayName(String name) {
		this.displayName = name;
	}

	/**
	 * Returns the internal name of the field in the bug repository
	 *
	 * @return the internal name of the field in the bug repository
	 */
	public String getTargetName() {
		return this.targetName;
	}

	/**
	 * Sets the internal name of the field in the bug repository
	 *
	 * @param targetName the internal name of the field in the bug repository
	 */
	public void setTargetName(String targetName) {
		this.targetName = targetName;
	}

	/**
	 * Returns the default value of the field, if one exists
	 *
	 * @return the default value of the field, if one exists
	 */
	public String getDefaultValue() {
		return this.defaultValue;
	}

	/**
	 * Sets the default value, and also initializes the value if it is not already set
	 *
	 * @param defaultValue the default value of the field
	 */
	public void setDefaultValue(String defaultValue) {
		this.defaultValue = defaultValue;
		
		// initialize value with default value
		if (this.value == null) {
			this.value = this.defaultValue;
		}
	}

	/**
	 * Returns the possible values of the field.  If the possible values are specified, then you cannot assign
	 * the value of this field to something other than a possible value
	 *
	 * @return the possible values of the field.  If the possible values are specified, then you cannot assign
	 * the value of this field to something other than a possible value
	 */
	public List<String> getPossibleValues() {
		return this.possibleValues;
	}

	/**
	 * Sets the possible values of this field.  If the field value is already set to something not contained in
	 * this list, then the value will be unset.
	 * @param possibleValues
	 */
	public void setPossibleValues(List<String> possibleValues) {
		this.possibleValues = possibleValues;
		
		String value = getValue();
		if (value != null && possibleValues != null && !possibleValues.contains(value)) {
			setValue(null);
		}
	}

	/**
	 * Returns the value of this field.
	 *
	 * @return the value of this field.
	 */
	public String getValue() {
		return this.value;
	}

	/**
	 * Sets the value of this field, and also notifies all of the field listeners
	 * @param value the field value
	 */
	public void setValue(String value) {
		this.value = value;
		
		for (BugtrackerFieldListener fieldListener : fieldListeners) {
			fieldListener.fieldValueChanged(this);
		}
	}

	/**
	 * Add a listener so that it will be notified when the value of the field changes
	 */
	public void addBugtrackerFieldListener(BugtrackerFieldListener listener) {
		fieldListeners.add(listener);
	}

	/**
	 * Remove a listener so that it will no longer be notified when the value of the field changes
	 */
	public void removeBugtrackerFieldListener(BugtrackerFieldListener listener) {
		fieldListeners.remove(listener);
	}
}
